/*
 * Copyright 2002-2021 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.context.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Enables support for handling components marked with AspectJ's {@code @Aspect} annotation,
 * similar to functionality found in Spring's {@code <aop:aspectj-autoproxy>} XML element.
 * To be used on @{@link Configuration} classes as follows:
 *
 * <pre class="code">
 * &#064;Configuration
 * &#064;EnableAspectJAutoProxy
 * public class AppConfig {
 *
 *     &#064;Bean
 *     public FooService fooService() {
 *         return new FooService();
 *     }
 *
 *     &#064;Bean
 *     public MyAspect myAspect() {
 *         return new MyAspect();
 *     }
 * }</pre>
 *
 * Where {@code FooService} is a typical POJO component and {@code MyAspect} is an
 * {@code @Aspect}-style aspect:
 *
 * <pre class="code">
 * public class FooService {
 *
 *     // various methods
 * }</pre>
 *
 * <pre class="code">
 * &#064;Aspect
 * public class MyAspect {
 *
 *     &#064;Before("execution(* FooService+.*(..))")
 *     public void advice() {
 *         // advise FooService methods as appropriate
 *     }
 * }</pre>
 *
 * In the scenario above, {@code @EnableAspectJAutoProxy} ensures that {@code MyAspect}
 * will be properly processed and that {@code FooService} will be proxied mixing in the
 * advice that it contributes.
 *
 * <p>Users can control the type of proxy that gets created for {@code FooService} using
 * the {@link #proxyTargetClass()} attribute. The following enables CGLIB-style 'subclass'
 * proxies as opposed to the default interface-based JDK proxy approach.
 *
 * <pre class="code">
 * &#064;Configuration
 * &#064;EnableAspectJAutoProxy(proxyTargetClass=true)
 * public class AppConfig {
 *     // ...
 * }</pre>
 *
 * <p>Note that {@code @Aspect} beans may be component-scanned like any other.
 * Simply mark the aspect with both {@code @Aspect} and {@code @Component}:
 *
 * <pre class="code">
 * package com.foo;
 *
 * &#064;Component
 * public class FooService { ... }
 *
 * &#064;Aspect
 * &#064;Component
 * public class MyAspect { ... }</pre>
 *
 * Then use the @{@link ComponentScan} annotation to pick both up:
 *
 * <pre class="code">
 * &#064;Configuration
 * &#064;ComponentScan("com.foo")
 * &#064;EnableAspectJAutoProxy
 * public class AppConfig {
 *
 *     // no explicit &#064;Bean definitions required
 * }</pre>
 *
 * <b>Note: {@code @EnableAspectJAutoProxy} applies to its local application context only,
 * allowing for selective proxying of beans at different levels.</b> Please redeclare
 * {@code @EnableAspectJAutoProxy} in each individual context, e.g. the common root web
 * application context and any separate {@code DispatcherServlet} application contexts,
 * if you need to apply its behavior at multiple levels.
 *
 * <p>This feature requires the presence of {@code aspectjweaver} on the classpath.
 * While that dependency is optional for {@code spring-aop} in general, it is required
 * for {@code @EnableAspectJAutoProxy} and its underlying facilities.
 *
 * AOP 术语解释：
 * 	切面(Aspect)：在 AOP 中指切面类 (通常被 @Aspect 标注)，管理着通知和切点
 * 	连接点(Join Point)：切面和被增强方法所连接的点（即代理方法，我们需要增强的方法）
 * 	通知(Advice)：某个特定的连接点上执行的动作，通常包括 前置(Before)，后置(After)，异常(Exception)，环绕(Around)
 * 	目标对象(Target)：需要被增强的对象，即包含业务逻辑类的对象
 * 	切点(PointCut)：匹配连接点的断言，由其决定哪些方法需要被增强，哪些不需要被增强，是AOP核心。Spring 默认使用 AspectJ 切点语义
 * 	顾问(Advisor)：通知 (Advice) 的一种包装体现。是 Advice 和 PointCut 的结合，无需应用关心
 * 	织入(Weaving)：将通知切入连接点的过程
 * 	引入(Introductions)：将其他接口和实现动态的引入targetClass中，不常用
 *
 * SpringAOP：
 * 	它基于动态代理来实现。默认地，如果使用接口的，用 JDK 提供的动态代理实现，如果没有接口，使用 CGLIB 实现
 * 		1、如果目标对象实现了接口，默认情况下会采用 JDK 的动态代理实现 AOP，可以强制使用 CGLIB 实现
 * 		2、如果目标对象没有实现了接口，必须采用 CGLIB 库，Spring 会自动在 JDK 动态代理和 CGLIB 之间转换
 * 	Spring 3.2 以后，spring-core 直接就把 CGLIB 和 ASM 的源码包括进来了，不需要显式引入依赖
 * 	Spring AOP 需要依赖于 IOC 容器来管理
 * 	Spring AOP 只能作用于 Spring 容器中的 Bean，使用纯粹的 Java 代码实现的，只能作用于 Bean 的方法
 * 	Spring 提供了 AspectJ 的支持，但只用到的AspectJ的切点解析和匹配
 *
 * Spring AOP 的配置方式：
 * 	Spring AOP 一共有三种配置方式，并且做到了很好的向下兼容
 * 		Spring 1.2 基于接口的配置：最早的 Spring AOP 是完全基于几个接口的，Spring 的事务就是此方式实现的
 * 			但是这种方式存在几个指明缺点：
 *				只能指定单一的 Bean 的 AOP，多个 Bean 需要创建多个 ProxyFactoryBean
 * 				添加一个通知我们就需要配置一个 MethodXxxxAdvice 或 MethodInterceptor 类
 * 				拦截器的粒度只控制到了类级别，类中所有的方法都进行了拦截
 * 		Spring 2.0 schema-based 配置：Spring 2.0 以后使用 XML 的方式来配置，使用命名空间
 * 		Spring 2.0 @AspectJ配置：使用注解的方式来配置
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.1
 * @see org.aspectj.lang.annotation.Aspect
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	/**
	 * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
	 * to standard Java interface-based proxies. The default is {@code false}.
	 */
	boolean proxyTargetClass() default false;

	/**
	 * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
	 * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
	 * Off by default, i.e. no guarantees that {@code AopContext} access will work.
	 * @since 4.3.1
	 */
	boolean exposeProxy() default false;

}
